/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.compomics.fspike.gui;

import com.compomics.fspike.contentprovider.fastaproviders.impl.UniprotFastaProvider;
import com.compomics.fspike.contentprovider.localprovider.ResourceContentProvider;
import com.compomics.fspike.contentprovider.toolkit.WebImageSourceProvider;
import com.compomics.fspike.gui.taxonomytree.rendering.DefaultTaxonomyTreeNode;
import com.compomics.fspike.contentprovider.webprovider.PubMedContentProvider;
import com.compomics.fspike.contentprovider.toolkit.WebProviderToolkit;
import com.compomics.fspike.contentprovider.uniprotontology.UniprotTaxonomyLookupService;
import com.compomics.fspike.contentprovider.webprovider.WikipediaContentProvider;
import static com.compomics.fspike.gui.NCBITaxonomyViewer.resize;
import com.compomics.fspike.gui.dialog.DialogSuggestedSearchTerms;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.tree.TreePath;
import javax.xml.parsers.ParserConfigurationException;

/**
 *
 * @author Kenneth
 */
public class UniprotTaxonomyViewer extends JFrame {

    //this textfield is used to fill in the selected taxonomy ID's in the fastabuildergui (or any other)
    protected JTextField textField;
    //the TreePath that enables us to remember where the selection happened (important for listeners such as the wikipedia function)
    protected TreePath currentSelectedPath;
    //list of relevant images for the searched taxonomy
    protected List<String> relevantImages = new ArrayList<>();
    //index to allow user to browse through images
    protected int currentImageIndex = 0;
    //visible image in the taxonomyviewer 
    protected ImageIcon icon;
    protected ImageIcon next_arrow_black;
    protected ImageIcon prev_arrow_black;
    protected ImageIcon next_arrow_grey;
    protected ImageIcon prev_arrow_grey;

    /**
     * Creates new form TaxonomyViewer
     *
     * @param textField this textfield will be filled with a list of selected
     * taxonomies
     * @throws java.net.MalformedURLException
     */
    public UniprotTaxonomyViewer(JTextField textField) throws MalformedURLException, IOException {
        super();
        initTaxonomyViewer();
    }

    /**
     * Creates new form TaxonomyViewer
     *
     * @throws java.net.MalformedURLException
     */
    public UniprotTaxonomyViewer() throws MalformedURLException, IOException {
        super();
        initTaxonomyViewer();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jPopupMenuForNodes = new javax.swing.JPopupMenu();
        selectOption = new javax.swing.JMenuItem();
        wikiOption = new javax.swing.JMenuItem();
        pubmedOption = new javax.swing.JMenuItem();
        commonAncestorOption = new javax.swing.JMenuItem();
        jPanel3 = new javax.swing.JPanel();
        cancelButton = new javax.swing.JButton();
        confirmButton = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();
        searchTextField = new javax.swing.JTextField();
        relatedImagePanel = new javax.swing.JPanel();
        relatedImageLabel = new javax.swing.JLabel();
        nextImageButton = new javax.swing.JButton();
        previousImageButton = new javax.swing.JButton();
        addButton = new javax.swing.JButton();
        removeButton = new javax.swing.JButton();
        jScrollPane2 = new javax.swing.JScrollPane();
        selectedTaxonomyList = new javax.swing.JList();
        searchButton = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jCheckBox1 = new javax.swing.JCheckBox();
        jScrollPane1 = new javax.swing.JScrollPane();
        try {
            taxonomyTree = new com.compomics.fspike.gui.taxonomytree.JUniprotTaxonomyTree();
        } catch (java.net.MalformedURLException e1) {
            e1.printStackTrace();
        }

        jPopupMenuForNodes.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                jPopupMenuForNodesMouseReleased(evt);
            }
        });

        selectOption.setText("Select");
        selectOption.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                selectOptionMouseClicked(evt);
            }
        });
        selectOption.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectOptionActionPerformed(evt);
            }
        });
        jPopupMenuForNodes.add(selectOption);

        wikiOption.setText("Visit Wikipedia");
        wikiOption.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                wikiOptionActionPerformed(evt);
            }
        });
        jPopupMenuForNodes.add(wikiOption);

        pubmedOption.setText("Visit Pubmed");
        pubmedOption.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                pubmedOptionActionPerformed(evt);
            }
        });
        jPopupMenuForNodes.add(pubmedOption);

        commonAncestorOption.setText("Find common ancestor");
        commonAncestorOption.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                commonAncestorOptionActionPerformed(evt);
            }
        });
        jPopupMenuForNodes.add(commonAncestorOption);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Compomics Taxonomy Browser");
        setBackground(new java.awt.Color(255, 255, 255));
        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));

        jPanel3.setBackground(new java.awt.Color(255, 255, 255));

        cancelButton.setText("Cancel");
        cancelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelButtonActionPerformed(evt);
            }
        });

        confirmButton.setText("OK");
        confirmButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                confirmButtonActionPerformed(evt);
            }
        });

        jPanel1.setBackground(new java.awt.Color(255, 255, 255));

        relatedImagePanel.setBackground(new java.awt.Color(255, 255, 255));
        relatedImagePanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Related Image"));

        relatedImageLabel.setBackground(new java.awt.Color(255, 255, 255));
        relatedImageLabel.setBorder(javax.swing.BorderFactory.createEtchedBorder());
        relatedImageLabel.setMaximumSize(new java.awt.Dimension(375, 375));
        relatedImageLabel.setMinimumSize(new java.awt.Dimension(375, 375));
        relatedImageLabel.setPreferredSize(new java.awt.Dimension(375, 375));

        nextImageButton.setText(">");
        nextImageButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                nextImageButtonActionPerformed(evt);
            }
        });

        previousImageButton.setText("<");
        previousImageButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                previousImageButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout relatedImagePanelLayout = new javax.swing.GroupLayout(relatedImagePanel);
        relatedImagePanel.setLayout(relatedImagePanelLayout);
        relatedImagePanelLayout.setHorizontalGroup(
            relatedImagePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(relatedImagePanelLayout.createSequentialGroup()
                .addGap(4, 4, 4)
                .addComponent(previousImageButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(relatedImageLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 321, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(nextImageButton)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        relatedImagePanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {nextImageButton, previousImageButton});

        relatedImagePanelLayout.setVerticalGroup(
            relatedImagePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(previousImageButton, javax.swing.GroupLayout.DEFAULT_SIZE, 217, Short.MAX_VALUE)
            .addComponent(nextImageButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(relatedImageLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
        );

        addButton.setText(">");
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });

        removeButton.setText("<");
        removeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeButtonActionPerformed(evt);
            }
        });

        jScrollPane2.setBorder(null);

        selectedTaxonomyList.setBorder(javax.swing.BorderFactory.createTitledBorder("Selected Taxonomies"));
        jScrollPane2.setViewportView(selectedTaxonomyList);

        searchButton.setText("Search");
        searchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchButtonActionPerformed(evt);
            }
        });

        jPanel2.setBackground(new java.awt.Color(255, 255, 255));
        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Uniprot Taxonomy Tree"));

        jCheckBox1.setBackground(new java.awt.Color(255, 255, 255));
        jCheckBox1.setText("Find only species with a complete proteome");

        jScrollPane1.setBorder(null);
        jScrollPane1.setViewportView(taxonomyTree);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jCheckBox1)
                .addContainerGap(198, Short.MAX_VALUE))
            .addComponent(jScrollPane1)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jCheckBox1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane1))
        );

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(searchTextField)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(searchButton))
                    .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(relatedImagePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(removeButton, javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(addButton, javax.swing.GroupLayout.Alignment.TRAILING))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 431, javax.swing.GroupLayout.PREFERRED_SIZE))))
        );

        jPanel1Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jScrollPane2, relatedImagePanel});

        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(searchButton))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(relatedImagePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 251, Short.MAX_VALUE)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addGap(0, 0, Short.MAX_VALUE)
                                .addComponent(addButton)
                                .addGap(18, 18, 18)
                                .addComponent(removeButton)
                                .addGap(87, 87, 87)))))
                .addContainerGap())
        );

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(cancelButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(confirmButton)
                .addContainerGap())
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        jPanel3Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, confirmButton});

        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(cancelButton)
                    .addComponent(confirmButton))
                .addGap(11, 11, 11))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed
        //see if node already exist !
        try {
            DefaultTaxonomyTreeNode foundNode = taxonomyTree
                    .searchNode((DefaultTaxonomyTreeNode) taxonomyTree.getModel().getRoot(), searchTextField.getText());
            if (foundNode == null) {
                //TODO urgently clean this up !
                List<DefaultTaxonomyTreeNode> queryPossibleNodes = UniprotTaxonomyLookupService.queryPossibleNode(searchTextField.getText(), 10, jCheckBox1.isSelected());
                HashMap<String, String> possibleDirections = new HashMap<>();
                HashMap<String, DefaultTaxonomyTreeNode> possibleNodes = new HashMap<>();
                for (DefaultTaxonomyTreeNode aNode : queryPossibleNodes) {
                    possibleDirections.put(aNode.toString(), aNode.getUrl());
                }

                StringBuilder selectedValue = new StringBuilder();
                DialogSuggestedSearchTerms confirmationDialog = new DialogSuggestedSearchTerms(possibleDirections, selectedValue, this, true);
                confirmationDialog.setVisible(true);

                for (DefaultTaxonomyTreeNode aNode : queryPossibleNodes) {
                    possibleNodes.put(aNode.toString(), aNode);
                }
                foundNode = possibleNodes.get(selectedValue.toString());
                try {
                    UniprotTaxonomyLookupService.updateNode(foundNode);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            taxonomyTree.buildSearchedPathToRoot(foundNode);
            updateImagesAndTree(foundNode);
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(this,
                    "Could not produce taxonomy tree : " + ex,
                    "Error during lookup",
                    JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_searchButtonActionPerformed

    private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
        this.setVisible(false);
    }//GEN-LAST:event_cancelButtonActionPerformed

    private void confirmButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_confirmButtonActionPerformed
        StringBuilder selectedTaxonomies = new StringBuilder();
        //merge into a single fasta
        DefaultListModel model = (DefaultListModel) selectedTaxonomyList.getModel();
        for (Object aTaxonomyID : model.toArray()) {
            String temp = aTaxonomyID.toString();
            // selectedTaxonomies.append(temp.split(":id ")[1]).append(",");
            selectedTaxonomies.append(temp).append(",");
        }
        //remove last ","
        selectedTaxonomies.setLength(selectedTaxonomies.length() - 1);
        textField.setText(selectedTaxonomies.toString());
        this.setVisible(false);
    }//GEN-LAST:event_confirmButtonActionPerformed

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
        //move selected taxonomies into the list
        TreePath[] selectionPaths = taxonomyTree.getSelectionPaths();
        for (TreePath aSelection : selectionPaths) {
            addSelectiontoList(aSelection);
        }
    }//GEN-LAST:event_addButtonActionPerformed


    private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed
        for (Object aSelectedEntry : selectedTaxonomyList.getSelectedValuesList()) {
            DefaultListModel model = (DefaultListModel) selectedTaxonomyList.getModel();
            model.removeElement(aSelectedEntry.toString());
        }
    }//GEN-LAST:event_removeButtonActionPerformed

    private void jPopupMenuForNodesMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jPopupMenuForNodesMouseReleased
        // TODO add your handling code here:
    }//GEN-LAST:event_jPopupMenuForNodesMouseReleased

    private void selectOptionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectOptionActionPerformed
        if (evt.getSource().equals(selectOption)) {
            addSelectiontoList(currentSelectedPath);
        }
    }//GEN-LAST:event_selectOptionActionPerformed

    private void selectOptionMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_selectOptionMouseClicked

    }//GEN-LAST:event_selectOptionMouseClicked

    private void wikiOptionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_wikiOptionActionPerformed
        String taxonomyName = currentSelectedPath.getLastPathComponent().toString();
        try {
            WebProviderToolkit.openBrowser(WikipediaContentProvider.getRelevantURL(taxonomyName));
        } catch (IOException | ParserConfigurationException ex) {
            JOptionPane.showMessageDialog(this,
                    "Could not find taxonomy ID for : " + taxonomyName,
                    "Error during lookup",
                    JOptionPane.WARNING_MESSAGE);
        }

    }//GEN-LAST:event_wikiOptionActionPerformed

    private void nextImageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nextImageButtonActionPerformed
        if (!relevantImages.isEmpty() && currentImageIndex < (relevantImages.size() - 1)) {
            currentImageIndex++;
        }
        try {
            loadRelevantImage(relevantImages.get(currentImageIndex));
        } catch (IndexOutOfBoundsException | IOException ex) {
            setDefaultImage();
        }
    }//GEN-LAST:event_nextImageButtonActionPerformed

    private void previousImageButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_previousImageButtonActionPerformed
        if (currentImageIndex > 0) {
            currentImageIndex--;
        }
        try {
            loadRelevantImage(relevantImages.get(currentImageIndex));
        } catch (IndexOutOfBoundsException | IOException ex) {
            setDefaultImage();
        }
    }//GEN-LAST:event_previousImageButtonActionPerformed

    private void pubmedOptionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pubmedOptionActionPerformed
        String taxonomyName = currentSelectedPath.getLastPathComponent().toString();
        try {
            WebProviderToolkit.openBrowser(PubMedContentProvider.getRelevantURL(taxonomyName));
        } catch (IOException | ParserConfigurationException ex) {
            JOptionPane.showMessageDialog(this,
                    "Could not find taxonomy ID for : " + taxonomyName,
                    "Error during lookup",
                    JOptionPane.WARNING_MESSAGE);
        }

    }//GEN-LAST:event_pubmedOptionActionPerformed

    private void commonAncestorOptionActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_commonAncestorOptionActionPerformed
        DefaultTaxonomyTreeNode commonAncestor = taxonomyTree.getCommonAncestor();
        System.out.println(commonAncestor);
    }//GEN-LAST:event_commonAncestorOptionActionPerformed

    protected void setDefaultImage() {
        try {
            icon = new ImageIcon();
            loadRelevantImage(ResourceContentProvider.getDefaultImageURL().toString());
        } catch (IOException ex) {
        }
    }

    protected void loadRelevantImage(String imageUrl) throws IOException {
        BufferedImage image = ImageIO.read(new URL(imageUrl));
        icon.setImage(resize(image, (int) relatedImageLabel.getSize().getWidth(), (int) relatedImageLabel.getSize().getHeight()));
        relatedImageLabel.setIcon(icon);
        relatedImageLabel.getParent().repaint();
        relatedImageLabel.getParent().revalidate();
    }

    /**
     *
     * @param image the image to resize
     * @param width the target width
     * @param height the target height
     * @return a resized buffered image
     */
    protected static BufferedImage resize(BufferedImage image, int width, int height) {
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) bi.createGraphics();
        g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
        g2d.drawImage(image, 0, 0, width, height, null);
        g2d.dispose();
        return bi;
    }

    /**
     * adds the selected node to the TreeModel. This is required to keep the
     * taxonomy ID in memory during multi-species lookups
     *
     * @param aSelection the selected path in the tree
     */
    protected void addSelectiontoList(TreePath aSelection) {
        DefaultTaxonomyTreeNode node = (DefaultTaxonomyTreeNode) aSelection.getLastPathComponent();
        String taxonomyName = node.toString();
        String taxonomyID = node.getTaxonomyID();
        if (taxonomyID == null) {
            JOptionPane.showMessageDialog(this,
                    "Could not find taxonomy ID for : " + taxonomyName,
                    "Error during lookup",
                    JOptionPane.ERROR_MESSAGE);
            node.setHasFasta(false);
        } else {
            if (UniprotFastaProvider.taxonomyHasFasta(taxonomyName)) {
                DefaultListModel model = (DefaultListModel) selectedTaxonomyList.getModel();
                model.addElement(taxonomyName + " (tax-id:" + taxonomyID + ")");
                node.setHasFasta(true);
                node.setSelectedForProcessing(true);
            } else {
                node.setHasFasta(false);
                JOptionPane.showMessageDialog(this,
                        "Fasta for : " + taxonomyName + " does not exist."
                        + "\nIt is suggested to chose either a relative species or a parent.",
                        "Fasta could not be found",
                        JOptionPane.WARNING_MESSAGE);
            }
        }
    }

    /**
     * Initializes the taxonomy viewer by setting up the gui and the tree itself
     *
     * @throws java.net.MalformedURLException
     */
    protected void initTaxonomyViewer() throws MalformedURLException {

        next_arrow_black = new ImageIcon(Toolkit.getDefaultToolkit().getImage(FastaBuilderGUI.class.getResource("/icons/next.png")));
        prev_arrow_black = new ImageIcon(Toolkit.getDefaultToolkit().getImage(FastaBuilderGUI.class.getResource("/icons/previous.png")));
        next_arrow_grey = new ImageIcon(Toolkit.getDefaultToolkit().getImage(FastaBuilderGUI.class.getResource("/icons/next_grey.png")));
        prev_arrow_grey = new ImageIcon(Toolkit.getDefaultToolkit().getImage(FastaBuilderGUI.class.getResource("/icons/previous_grey.png")));
        this.setIconImage(Toolkit.getDefaultToolkit().getImage(FastaBuilderGUI.class.getResource("/icons/temp_icon_orange.png")));
        initComponents();
        searchButton.setMnemonic(KeyEvent.VK_ENTER);
        nextImageButton.setIcon(next_arrow_grey);
        nextImageButton.setText("");
        previousImageButton.setIcon(prev_arrow_grey);
        previousImageButton.setText("");
        addButton.setIcon(next_arrow_black);
        addButton.setText("");
        removeButton.setIcon(prev_arrow_black);
        removeButton.setText("");
        setDefaultImage();
        selectedTaxonomyList.setModel(new DefaultListModel());
        addMouseListenerToTree();
        addKeyListenerToTree();
        //set fullscreen
        this.setExtendedState(this.MAXIMIZED_BOTH);
    }

    /**
     * adds a mouselistener to the jTree. This listener is used to detect mouse
     * events that double click a node to expand it.
     *
     */
    protected void addMouseListenerToTree() {
        MouseListener ml;
        ml = new MouseAdapter() {

            @Override
            public void mousePressed(MouseEvent e) {
                if (e.getModifiers() != InputEvent.BUTTON3_MASK) {
                    TreePath selPath = taxonomyTree.getPathForLocation(e.getX(), e.getY());
                    if (selPath != null && e.getClickCount() == 2) {
                        DefaultTaxonomyTreeNode selectedNode = (DefaultTaxonomyTreeNode) selPath.getLastPathComponent();
                        try {
                            if (selectedNode != null) {
                                taxonomyTree.setModel(taxonomyTree.openChildren(selectedNode));
                                //select the first child?
                                if (selectedNode.getChildCount() > 0) {
                                    selectedNode = (DefaultTaxonomyTreeNode) selectedNode.children().nextElement();
                                }
                                updateImagesAndTree(selectedNode);
                            }
                        } catch (IOException ex) {
                            Logger.getLogger(NCBITaxonomyViewer.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                } else {
                    commonAncestorOption.setEnabled(taxonomyTree.getSelectionPaths().length > 1);
                    currentSelectedPath = taxonomyTree.getPathForLocation(e.getX(), e.getY());
                    Rectangle pathBounds = taxonomyTree.getUI().getPathBounds(taxonomyTree, currentSelectedPath);
                    if (pathBounds != null && pathBounds.contains(e.getX(), e.getY())) {
                        jPopupMenuForNodes.show(taxonomyTree, pathBounds.x, pathBounds.y + pathBounds.height);
                    }
                }
            }
        };
        taxonomyTree.addMouseListener(ml);
    }

    /**
     * adds a keyListener to the jTree. This listener is used to detect right
     * arrow events that double click a node to expand it.
     *
     */
    protected void addKeyListenerToTree() {
        KeyAdapter kl;
        kl = new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int key = e.getKeyCode();
                if (key == KeyEvent.VK_KP_RIGHT || key == KeyEvent.VK_RIGHT) {
                    currentSelectedPath = taxonomyTree.getSelectionPath();
                    if (currentSelectedPath != null) {
                        DefaultTaxonomyTreeNode selectedNode = (DefaultTaxonomyTreeNode) currentSelectedPath.getLastPathComponent();
                        try {
                            if (selectedNode != null) {
                                taxonomyTree.setModel(taxonomyTree.openChildren(selectedNode));
                                //select the first child?
                                if (selectedNode.getChildCount() > 0) {
                                    selectedNode = (DefaultTaxonomyTreeNode) selectedNode.children().nextElement();
                                }
                                updateImagesAndTree(selectedNode);
                            }
                        } catch (IOException ex) {
                            Logger.getLogger(NCBITaxonomyViewer.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
            }
        };
        taxonomyTree.addKeyListener(kl);
    }

    protected void updateImagesAndTree(DefaultTaxonomyTreeNode selectedNode) throws IOException {
        if (selectedNode != null) {
            //see if node exists now and select it !
            taxonomyTree.openChildren(selectedNode);
            currentSelectedPath = new TreePath(selectedNode.getPath());
            taxonomyTree.setSelectionPath(currentSelectedPath);
            taxonomyTree.scrollPathToVisible(currentSelectedPath);
            relevantImages = WebImageSourceProvider.getImageURLsForTaxonomy(selectedNode.toString());
            if (relevantImages.isEmpty()) {
                try {
                    relevantImages.add(ResourceContentProvider.getDefaultImageURL().toString());
                    currentImageIndex = 0;
                    loadRelevantImage(relevantImages.get(currentImageIndex));
                } catch (IOException ex) {
                    Logger.getLogger(NCBITaxonomyViewer.class.getName()).log(Level.SEVERE, null, ex);
                }
                nextImageButton.setIcon(next_arrow_grey);
                previousImageButton.setIcon(prev_arrow_grey);
            } else {
                nextImageButton.setIcon(next_arrow_black);
                previousImageButton.setIcon(prev_arrow_black);
            }
        }
        try {
            loadRelevantImage(relevantImages.get(0));
        } catch (IOException ex) {
            Logger.getLogger(NCBITaxonomyViewer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Metal".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(UniprotTaxonomyViewer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(UniprotTaxonomyViewer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(UniprotTaxonomyViewer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(UniprotTaxonomyViewer.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new UniprotTaxonomyViewer(new JTextField()).setVisible(true);
                } catch (MalformedURLException ex) {
                    Logger.getLogger(UniprotTaxonomyViewer.class.getName()).log(Level.SEVERE, null, ex);
                } catch (IOException ex) {
                    Logger.getLogger(UniprotTaxonomyViewer.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addButton;
    private javax.swing.JButton cancelButton;
    private javax.swing.JMenuItem commonAncestorOption;
    private javax.swing.JButton confirmButton;
    private javax.swing.JCheckBox jCheckBox1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPopupMenu jPopupMenuForNodes;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JButton nextImageButton;
    private javax.swing.JButton previousImageButton;
    private javax.swing.JMenuItem pubmedOption;
    private javax.swing.JLabel relatedImageLabel;
    private javax.swing.JPanel relatedImagePanel;
    private javax.swing.JButton removeButton;
    private javax.swing.JButton searchButton;
    private javax.swing.JTextField searchTextField;
    private javax.swing.JMenuItem selectOption;
    private javax.swing.JList selectedTaxonomyList;
    private com.compomics.fspike.gui.taxonomytree.JUniprotTaxonomyTree taxonomyTree;
    private javax.swing.JMenuItem wikiOption;
    // End of variables declaration//GEN-END:variables

}
